package com.zzedu.manager.impl;

import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.zzedu.common.enums.CommonEnums;
import com.zzedu.common.exception.ServiceException;
import com.zzedu.common.utils.SecurityUtils;
import com.zzedu.common.utils.StringUtils;
import com.zzedu.device.req.*;
import com.zzedu.device.rsp.*;
import com.zzedu.domain.*;
import com.zzedu.dto.StudentExerciseReportDTO;
import com.zzedu.enmuns.ConfigEnums;
import com.zzedu.enmuns.InteractionTypeEnums;
import com.zzedu.framework.transaction.ITransactionHandlerService;
import com.zzedu.manager.ITeacherStudentManager;
import com.zzedu.manager.IZzUploadFileManager;
import com.zzedu.result.Result;
import com.zzedu.result.ResultEnum;
import com.zzedu.service.*;
import com.zzedu.system.service.ISysConfigService;
import com.zzedu.utils.PageData;
import com.zzedu.vo.ZzUploadFileVO;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.collections4.MapUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

@Component
public class TeacherStudentManagerImpl implements ITeacherStudentManager {
    @Autowired
    IZzExerciseBookSubmitContentService zzExerciseBookSubmitContentService;

    @Autowired
    IZzStudentService zzStudentService;

    @Autowired
    IZzPictureNodeService zzPictureNodeService;

    @Autowired
    ISysConfigService sysConfigService;

    @Autowired
    IZzSubjectContentService zzSubjectContentService;

    @Autowired
    IZzExerciseBookService zzExerciseBookService;

    @Autowired
    IZzClassesSendStudentService zzClassesSendStudentService;

    @Autowired
    IZzTeacherService zzTeacherService;

    @Autowired
    IZzPictureBookService zzPictureBookService;

    @Autowired
    ITransactionHandlerService transactionHandlerService;

    @Autowired
    IZzUploadFileManager zzUploadFileManager;

    @Autowired
    IZzSchoolCourseService zzSchoolCourseService;

    @Autowired
    IZzClassesService zzClassesService;

    @Autowired
    IZzCourseService zzCourseService;

    @Autowired
    IZzZzStuClassesRService zzZzStuClassesRService;

    @Autowired
    IZzStudentExtendService zzStudentExtendService;

    @Override
    public Result<List<ApiStuLearnVO>> stuLearnList(TeacherStuClassPageList data) {
        Result<List<ApiStuLearnVO>> result = new Result<>();
        //班级学生列表
        List<ZzStudent> zzStudentList = zzStudentService.list(Wrappers.lambdaQuery(ZzStudent.class).apply("id in(select stu_id from zz_stu_classes_r where deleted=0 and class_id={0})", data.getId()).orderByAsc(ZzStudent::getId));
        if (CollectionUtils.isNotEmpty(zzStudentList)) {
            List<ApiStuLearnVO> apiStuLearnVOList = Lists.newArrayList();
            Long count = zzSubjectContentService.getCountByBookId(data.getBookId());
            BigDecimal limit = new BigDecimal("100");
            if (null != count && count > 0) {
                List<StudentExerciseReportDTO> studentExerciseReportDTOList = zzExerciseBookSubmitContentService.getStudentExerciseReport(data.getId(), data.getBookId(), zzStudentList.stream().map(ZzStudent::getId).collect(Collectors.toList()));
                Map<Long, StudentExerciseReportDTO> map = Optional.ofNullable(studentExerciseReportDTOList).orElse(Lists.newArrayList()).stream().collect(Collectors.toMap(StudentExerciseReportDTO::getStudentId, Function.identity(), (k1, k2) -> k2));
                for (ZzStudent zzStudent : zzStudentList) {
                    ApiStuLearnVO apiStuLearnVO = new ApiStuLearnVO();
                    apiStuLearnVO.setId(zzStudent.getId());
                    apiStuLearnVO.setName(zzStudent.getStuName());
                    apiStuLearnVO.setBookId(data.getBookId());
                    apiStuLearnVO.setRightRatio("0");
                    apiStuLearnVO.setFinishRatio("0");
                    StudentExerciseReportDTO studentExerciseReportDTO = map.get(zzStudent.getId());
                    if (null != studentExerciseReportDTO) {
                        BigDecimal finishRatio = new BigDecimal(String.valueOf(studentExerciseReportDTO.getTotalCount() * 100)).divide(new BigDecimal(String.valueOf(count)), 2, BigDecimal.ROUND_HALF_UP);
                        if (limit.compareTo(finishRatio) == -1) {
                            finishRatio = limit;
                        }
                        //完成率
                        apiStuLearnVO.setFinishRatio(finishRatio.stripTrailingZeros().toPlainString());

                        //正确率
                        apiStuLearnVO.setFinishRatio(new BigDecimal(String.valueOf(studentExerciseReportDTO.getCorrectCount() * 100)).divide(new BigDecimal(String.valueOf(studentExerciseReportDTO.getSubmitCount())), 2, BigDecimal.ROUND_HALF_UP).stripTrailingZeros().toPlainString());
                    }
                    apiStuLearnVOList.add(apiStuLearnVO);
                }
            } else {
                for (ZzStudent zzStudent : zzStudentList) {
                    ApiStuLearnVO apiStuLearnVO = new ApiStuLearnVO();
                    apiStuLearnVO.setId(zzStudent.getId());
                    apiStuLearnVO.setName(zzStudent.getStuName());
                    apiStuLearnVO.setBookId(data.getBookId());
                    apiStuLearnVO.setRightRatio("0");
                    apiStuLearnVO.setFinishRatio("0");
                    apiStuLearnVOList.add(apiStuLearnVO);
                }
            }
            result.setData(apiStuLearnVOList);
        }
        result.setResultMessage(ResultEnum.SUCCESS.getDesc());
        result.setResultCode(ResultEnum.SUCCESS.getCode());
        return result;
    }

    @Override
    public Result<List<ApiStuLearnNodeInfoVO>> stuLearnNodeInfo(TeacherStuClassInfo data) {
        //获取绘本DAYS
        LambdaQueryWrapper<ZzPictureNode> lambdaQueryWrapper = Wrappers.lambdaQuery(ZzPictureNode.class);
        lambdaQueryWrapper.eq(ZzPictureNode::getPictureBookId, data.getBookId());
        lambdaQueryWrapper.in(ZzPictureNode::getNodeType, 3);
        lambdaQueryWrapper.orderByAsc(ZzPictureNode::getSortNo).orderByAsc(ZzPictureNode::getId);
        List<ZzPictureNode> zzPictureNodeList = zzPictureNodeService.list(lambdaQueryWrapper);
        List<ApiStuLearnNodeInfoVO> learnNodeInfoVOList = Lists.newArrayList();
        String config = sysConfigService.selectConfigByKeyCache(ConfigEnums.TASK_PICTURE_NODE_ICON.getCode());
        JSONObject obj = new JSONObject();
        if (StringUtils.isNotBlank(config)) {
            obj = JSON.parseObject(config);
        }
        if (CollectionUtils.isNotEmpty(zzPictureNodeList)) {
            for (ZzPictureNode zzPictureNode : zzPictureNodeList) {
                ApiStuLearnNodeInfoVO apiStuLearnNodeInfoVO = new ApiStuLearnNodeInfoVO();
                apiStuLearnNodeInfoVO.setNodeName(zzPictureNode.getNodeName());
                apiStuLearnNodeInfoVO.setNodeIconUrl(MapUtils.getString(obj, zzPictureNode.getNodeName() + "_s", ""));
                //计算下级别数据
                lambdaQueryWrapper = Wrappers.lambdaQuery(ZzPictureNode.class);
                lambdaQueryWrapper.eq(ZzPictureNode::getpNodeId, zzPictureNode.getId());
                lambdaQueryWrapper.orderByAsc(ZzPictureNode::getSortNo).orderByAsc(ZzPictureNode::getId);
                List<ZzPictureNode> zzPictureNodes = zzPictureNodeService.list(lambdaQueryWrapper);
                List learnData = Lists.newArrayList();
                if (CollectionUtils.isNotEmpty(zzPictureNodes)) {
                    for (ZzPictureNode childZzPictureNode : zzPictureNodes) {
                        //题目数 # 答题数
                        long subjectCount = zzSubjectContentService
                                .count(Wrappers.lambdaQuery(ZzSubjectContent.class)
                                        .eq(ZzSubjectContent::getNodeId, childZzPictureNode.getId()));
                        if (subjectCount > 0) {
                            //配置了题目在展示
                            Map map = new HashMap();
                            map.put("title", childZzPictureNode.getNodeName());
                            map.put("ratio", "0");
                            map.put("iconURL", MapUtils.getString(obj, childZzPictureNode.getNodeName() + "_s", ""));

                            //答题数
                            long answerCount = zzExerciseBookService.count(Wrappers.lambdaQuery(ZzExerciseBook.class)
                                    .eq(ZzExerciseBook::getNodeId, childZzPictureNode.getId())
                                    .eq(ZzExerciseBook::getPictureBookId, data.getBookId())
                                    .eq(ZzExerciseBook::getStudentId, data.getStuId())
                                    );
                            map.put("ratio", new BigDecimal(String.valueOf(answerCount * 100))
                                    .divide(new BigDecimal(String.valueOf(subjectCount)), 2, BigDecimal.ROUND_HALF_UP)
                                    .stripTrailingZeros().toPlainString());
                            if(answerCount>subjectCount){
                                map.put("ratio","100");
                            }

                            learnData.add(map);
                        }

                    }
                }
                apiStuLearnNodeInfoVO.setLearnData(learnData);
                learnNodeInfoVOList.add(apiStuLearnNodeInfoVO);
            }
        }
        Result<List<ApiStuLearnNodeInfoVO>> result = new Result<>();
        result.setResultMessage(ResultEnum.SUCCESS.getDesc());
        result.setResultCode(ResultEnum.SUCCESS.getCode());
        result.setData(learnNodeInfoVOList);
        return result;
    }

    @Override
    public Result distribute(Distribute data) {
        ZzTeacher zzTeacher = this.zzTeacherService.getById(SecurityUtils.getUserId());
        ZzPictureBook zzPictureBook = this.zzPictureBookService.getById(data.getId());
        return transactionHandlerService.runInTransaction(() -> {
            for (Long id : data.getStuId()) {
                ZzClassesSendStudent zzClassesSendStudent = new ZzClassesSendStudent();
                zzClassesSendStudent.setBookId(data.getId());
                zzClassesSendStudent.setStuId(id);
                zzClassesSendStudent.setBusDate(LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd")));
                zzClassesSendStudent.setTeacherId(zzTeacher.getId());
                zzClassesSendStudent.setClzzId(data.getClzzId());
                zzClassesSendStudent.setUnitId(zzPictureBook.getUnitId());
                zzClassesSendStudent.setUnLockDate(LocalDateTime.now());
                zzClassesSendStudent.setSchoolId(zzTeacher.getSchoolId());
                zzClassesSendStudentService.save(zzClassesSendStudent);
                LambdaUpdateWrapper<ZzStudentExtend> updateWrapper = Wrappers.lambdaUpdate(ZzStudentExtend.class);
                updateWrapper.eq(ZzStudentExtend::getId, id);
                updateWrapper.setDecrBy(ZzStudentExtend::getNumberOfClassHours, 1);
                updateWrapper.ge(ZzStudentExtend::getNumberOfClassHours, 1);
                boolean res = zzStudentExtendService.update(updateWrapper);
                if (!res) {
                    throw new ServiceException("当前学生课时不足,无法进行作业派发");
                }
            }
            Result result = new Result();
            result.setResultMessage(ResultEnum.SUCCESS.getDesc());
            result.setResultCode(ResultEnum.SUCCESS.getCode());
            return result;
        });
    }

    @Override
    public Result<PageData<ApiDistributeList>> distributeList(QueryPageDistributeList data) {
        Result<PageData<ApiDistributeList>> result = new Result<>();
        IPage<Map<String, Object>> page = zzClassesSendStudentService.queryStudentsByClassIdAndBookId(Page.of(data.getPageNum(), data.getPageSize()), data.getClzzId(), data.getId());
        PageData<ApiDistributeList> pageData = new PageData<>();
        pageData.setTotal(page.getTotal());
        pageData.setRowData(Lists.newArrayList());


        if (CollectionUtils.isNotEmpty(page.getRecords())) {
            List<Long> fileId = Lists.newArrayList();
            List<Long> stuId = Lists.newArrayList();
            boolean unLockFlag = false;
            for (Map map : page.getRecords()) {
                ApiDistributeList apiDistributeList = new ApiDistributeList();
                apiDistributeList.setExpireAt(MapUtils.getString(map, "expireAt"));
                apiDistributeList.setIsSend(MapUtils.getLong(map, "id", null) == null ? CommonEnums.NO : CommonEnums.YES);
                apiDistributeList.setName(MapUtils.getString(map, "stuName"));
                apiDistributeList.setAvatar(MapUtils.getString(map, "avatar", null));
                apiDistributeList.setNickName(MapUtils.getString(map, "nickName"));
                apiDistributeList.setId(MapUtils.getLong(map, "stuId"));
                fileId.add(MapUtils.getLong(map, "avatar"));
                stuId.add(MapUtils.getLong(map, "stuId"));
                pageData.getRowData().add(apiDistributeList);
                if (CommonEnums.YES == apiDistributeList.getIsSend()) {
                    unLockFlag = true;
                }
            }
            List<ZzStudentExtend> zzStudentExtendList = zzStudentExtendService.listByIds(stuId);
            Map<Long, ZzUploadFileVO> avatarMap = zzUploadFileManager.getMapByIdList(fileId);
            Map<Long, StudentExerciseReportDTO> submitResultMap = Maps.newHashMap();
            Map<Long, ZzStudentExtend> zzStudentExtendMap = Optional.ofNullable(zzStudentExtendList).orElse(Lists.newArrayList()).stream().collect(Collectors.toMap(ZzStudentExtend::getId, Function.identity(), (k1, k2) -> k2));
            Long count = 0L;
            if (unLockFlag) {
                List<StudentExerciseReportDTO> studentExerciseReportDTOList = zzExerciseBookSubmitContentService.getStudentExerciseReport(data.getClzzId(), data.getId(), pageData.getRowData().stream().map(ApiDistributeList::getId).collect(Collectors.toList()));
                submitResultMap = Optional.ofNullable(studentExerciseReportDTOList).orElse(Lists.newArrayList()).stream().collect(Collectors.toMap(StudentExerciseReportDTO::getStudentId, Function.identity(), (k1, k2) -> k2));
                count = zzSubjectContentService.getCountByBookId(data.getId());
            }
            for (ApiDistributeList apiDistributeList : pageData.getRowData()) {
                if (null != apiDistributeList.getAvatar()) {
                    ZzUploadFileVO zzUploadFileVO = avatarMap.get(Long.valueOf(apiDistributeList.getAvatar()));
                    if (null != zzUploadFileVO) {
                        apiDistributeList.setAvatar(zzUploadFileVO.getUrl());
                    }
                }
                apiDistributeList.setRightRatio("0");
                apiDistributeList.setFinishRatio("0");
                apiDistributeList.setNumberOfClassHours(0);
                StudentExerciseReportDTO studentExerciseReportDTO = submitResultMap.get(apiDistributeList.getId());
                if (null != studentExerciseReportDTO) {
                    //完成率
                    apiDistributeList.setFinishRatio(new BigDecimal(String.valueOf(studentExerciseReportDTO.getTotalCount() * 100)).divide(new BigDecimal(String.valueOf(count)), 2, BigDecimal.ROUND_HALF_UP).stripTrailingZeros().toPlainString());
                    if(studentExerciseReportDTO.getTotalCount()>count){
                        apiDistributeList.setFinishRatio("100");
                    }
                    //正确率
                    apiDistributeList.setRightRatio(new BigDecimal(String.valueOf(studentExerciseReportDTO.getCorrectCount() * 100)).divide(new BigDecimal(String.valueOf(studentExerciseReportDTO.getSubmitCount())), 2, BigDecimal.ROUND_HALF_UP).stripTrailingZeros().toPlainString());
                }
                ZzStudentExtend zzStudentExtend = zzStudentExtendMap.get(apiDistributeList.getId());
                if (null != zzStudentExtend) {
                    apiDistributeList.setNumberOfClassHours(zzStudentExtend.getNumberOfClassHours());
                }
            }
        }
        result.setData(pageData);
        result.setResultMessage(ResultEnum.SUCCESS.getDesc());
        result.setResultCode(ResultEnum.SUCCESS.getCode());
        return result;
    }

    @Override
    public Result<PageData<ApiDistributeHistory>> distributeHistory(QueryPageDistributeHistory data) {
        ZzTeacher zzTeacher = this.zzTeacherService.getById(SecurityUtils.getUserId());

        LambdaQueryWrapper<ZzClassesSendStudent> lambdaQueryWrapper = Wrappers.lambdaQuery(ZzClassesSendStudent.class);
        lambdaQueryWrapper.eq(null != data.getId(), ZzClassesSendStudent::getStuId, data.getId());
        lambdaQueryWrapper.eq(ZzClassesSendStudent::getSchoolId, zzTeacher.getSchoolId());
        lambdaQueryWrapper.eq(ZzClassesSendStudent::getTeacherId, zzTeacher.getId());
        lambdaQueryWrapper.le(null != data.getEndDate(), ZzClassesSendStudent::getUnLockDate, data.getEndDate());
        lambdaQueryWrapper.ge(null != data.getStartDate(), ZzClassesSendStudent::getUnLockDate, data.getStartDate());
        if (StringUtils.isNotBlank(data.getStuName())) {
            lambdaQueryWrapper.apply("stu_id in(select id from zz_student where deleted=0 and stu_name like concat('%', {0}, '%'))", data.getStuName());
        }
        lambdaQueryWrapper.orderByDesc(ZzClassesSendStudent::getId);
        IPage<ZzClassesSendStudent> page = this.zzClassesSendStudentService.page(Page.of(data.getPageNum(), data.getPageSize()), lambdaQueryWrapper);

        Result<PageData<ApiDistributeHistory>> result = new Result<>();
        PageData<ApiDistributeHistory> pageData = new PageData<>();
        pageData.setTotal(page.getTotal());
        pageData.setRowData(Lists.newArrayList());
        if (CollectionUtils.isNotEmpty(page.getRecords())) {

            List<ZzStudent> zzStudentList = this.zzStudentService.listByIds(page.getRecords().stream().map(ZzClassesSendStudent::getStuId).collect(Collectors.toList()));
            Map<Long, ZzStudent> zzStudentMap = Optional.ofNullable(zzStudentList).orElse(Lists.newArrayList()).stream().collect(Collectors.toMap(ZzStudent::getId, Function.identity(), (k1, k2) -> k2));
            for (ZzClassesSendStudent zzClassesSendStudent : page.getRecords()) {
                ApiDistributeHistory apiDistributeHistory = new ApiDistributeHistory();
                apiDistributeHistory.setGmtCreate(zzClassesSendStudent.getUnLockDate());
                apiDistributeHistory.setNickName("已注销");
                apiDistributeHistory.setId(zzClassesSendStudent.getId());
                ZzCourse zzCourse = this.zzCourseService.getById(zzClassesSendStudent.getUnitId());
                if (null != zzCourse) {
                    apiDistributeHistory.setUnitTitle(zzCourse.getName());
                }
                ZzPictureBook pictureBook = this.zzPictureBookService.getById(zzClassesSendStudent.getBookId());
                if (null != pictureBook) {
                    apiDistributeHistory.setBookTitle(pictureBook.getName());
                }
                ZzStudent zzStudent = zzStudentMap.get(zzClassesSendStudent.getStuId());
                if (null != zzStudent) {
                    apiDistributeHistory.setExpireAt(zzStudent.getValidTo());
                    apiDistributeHistory.setName(zzStudent.getStuName());
                    apiDistributeHistory.setNickName(zzStudent.getNickName());
                    if (null != zzStudent.getAvatar()) {
                        ZzUploadFileVO zzUploadFileVO = this.zzUploadFileManager.getById(zzStudent.getAvatar());
                        apiDistributeHistory.setAvatar(null);
                        if (null != zzUploadFileVO) {
                            apiDistributeHistory.setAvatar(zzUploadFileVO.getUrl());
                        }
                    }
                }
                pageData.getRowData().add(apiDistributeHistory);
            }


        }
        result.setResultMessage(ResultEnum.SUCCESS.getDesc());
        result.setResultCode(ResultEnum.SUCCESS.getCode());
        result.setData(pageData);
        return result;
    }

    @Override
    public Result<ApiTeacherInfoVO> teacherInfo() {
        Result<ApiTeacherInfoVO> result = new Result<>();
        ZzTeacher zzTeacher = this.zzTeacherService.getById(SecurityUtils.getUserId());
        ApiTeacherInfoVO apiTeacherInfoVO = new ApiTeacherInfoVO();
        apiTeacherInfoVO.setName(zzTeacher.getName());
        Map map = zzZzStuClassesRService.studentCountAndClzzCountByTeacherId(SecurityUtils.getUserId());
        apiTeacherInfoVO.setStuCount(MapUtils.getLong(map, "stuCount", 0L));
        apiTeacherInfoVO.setClzzCount(MapUtils.getLong(map, "clzzCount", 0L));
        result.setResultMessage(ResultEnum.SUCCESS.getDesc());
        result.setResultCode(ResultEnum.SUCCESS.getCode());
        result.setData(apiTeacherInfoVO);
        return result;
    }
}
